﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace Lilium.Web.Mvc
{
	public static class ScriptResourceReflectionHelper
	{
		public static IEnumerable<IScriptResourceReference> GetResourceReferences<T>()
		{
			return GetResourceReferences(typeof(T));
		}

		public static IEnumerable<IScriptResourceReference> GetResourceReferences(Type reflectedType)
		{
			IEnumerable<IScriptResourceReference> resourceReferences;
			lock (ScriptResourceReflectionCache)
				if (!ScriptResourceReflectionCache.TryGetValue(reflectedType, out resourceReferences))
				{
					resourceReferences = ReflectResourceReferences(reflectedType);
					ScriptResourceReflectionCache[reflectedType] = resourceReferences;
				}
			return resourceReferences;
		}

		private static IEnumerable<IScriptResourceReference> ReflectResourceReferences(Type reflectedType)
		{
			if (reflectedType == null)
				throw new ArgumentNullException("reflectedType");

			var inheritanceStack = new Stack<Type>();
			while (reflectedType != typeof(object))
			{
				inheritanceStack.Push(reflectedType);
				reflectedType = reflectedType.BaseType;
			}

			while (inheritanceStack.Count != 0)
			{
				reflectedType = inheritanceStack.Pop();
				foreach (var attribute in reflectedType.GetCustomAttributes(typeof(ScriptResourceReferenceAttribute), false).Cast<ScriptResourceReferenceAttribute>().OrderBy(a => a.LoadOrder))
					foreach (var resourceReference in attribute.GetResourceReferences())
						yield return resourceReference;
				reflectedType = reflectedType.BaseType;
			}
		}

		#region private static Dictionary<Type, IEnumerable<IScriptResourceReference>> ScriptResourceReflectionCache

		private static readonly Dictionary<Type, IEnumerable<IScriptResourceReference>> m_ScriptResourceReflectionCache = new Dictionary<Type, IEnumerable<IScriptResourceReference>>();

		private static Dictionary<Type, IEnumerable<IScriptResourceReference>> ScriptResourceReflectionCache { [DebuggerNonUserCodeAttribute] get { return m_ScriptResourceReflectionCache; } }

		#endregion
	}
}